package net.jgrm.redisadvanced.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import net.jgrm.redisadvanced.bloomfilter.RedisBloomFilterService;
import net.jgrm.redisadvanced.bloomfilter.RedisBloomFilterServiceImpl;
import net.jgrm.redisadvanced.lock.RedisLockService;
import net.jgrm.redisadvanced.lock.RedisLockServiceImpl;
import net.jgrm.redisadvanced.service.*;
import net.jgrm.redisadvanced.service.impl.*;
import org.redisson.api.RedissonClient;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis高级功能自动配置类
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(RedisAdvancedProperties.class)
@ConditionalOnClass(RedisTemplate.class)
@ConditionalOnProperty(prefix = "redis.advanced", name = "enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter({RedisAutoConfiguration.class, org.redisson.spring.starter.RedissonAutoConfiguration.class})
public class RedisAdvancedAutoConfiguration {

    /**
     * 配置RedisTemplate，支持对象的序列化和反序列化
     */
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 设置key序列化器
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);

        // 设置value序列化器
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        log.info("RedisTemplate配置完成");
        return redisTemplate;
    }

    /**
     * 配置ObjectMapper
     */
    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        return objectMapper;
    }

    /**
     * 配置String类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisStringService redisStringService(RedisTemplate<String, Object> redisTemplate,
                                                 RedisAdvancedProperties redisAdvancedProperties,
                                                 ObjectMapper objectMapper) {
        RedisStringServiceImpl service = new RedisStringServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis String类型操作服务初始化完成");
        return service;
    }


    @Bean
    @ConditionalOnMissingBean
    public RedisGeoService redisGeoService(RedisTemplate<String, Object> redisTemplate) {
        RedisGeoServiceImpl service = new RedisGeoServiceImpl<>(redisTemplate);
        log.info("Redis GEO 类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置List类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisListService redisListService(RedisTemplate<String, Object> redisTemplate,
                                             RedisAdvancedProperties redisAdvancedProperties,
                                             ObjectMapper objectMapper) {
        RedisListServiceImpl service = new RedisListServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis List类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置Hash类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisHashService redisHashService(RedisTemplate<String, Object> redisTemplate,
                                             RedisAdvancedProperties redisAdvancedProperties,
                                             ObjectMapper objectMapper) {
        RedisHashServiceImpl service = new RedisHashServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis Hash类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置Set类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisSetService redisSetService(RedisTemplate<String, Object> redisTemplate,
                                           RedisAdvancedProperties redisAdvancedProperties,
                                           ObjectMapper objectMapper) {
        RedisSetServiceImpl service = new RedisSetServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis Set类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置ZSet类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisZSetService redisZSetService(RedisTemplate<String, Object> redisTemplate,
                                             RedisAdvancedProperties redisAdvancedProperties,
                                             ObjectMapper objectMapper) {
        RedisZSetServiceImpl service = new RedisZSetServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis ZSet类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置HyperLogLog类型操作服务
     */
    @Bean
    @ConditionalOnMissingBean
    public RedisHyperLogLogService redisHyperLogLogService(RedisTemplate<String, Object> redisTemplate,
                                                           RedisAdvancedProperties redisAdvancedProperties) {
        RedisHyperLogLogServiceImpl service = new RedisHyperLogLogServiceImpl(redisTemplate, redisAdvancedProperties);
        log.info("Redis HyperLogLog类型操作服务初始化完成");
        return service;
    }

    /**
     * 配置布隆过滤器服务
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "redis.advanced.bloom-filter", name = "enabled", havingValue = "true", matchIfMissing = true)
    public RedisBloomFilterService redisBloomFilterService(RedisTemplate<String, Object> redisTemplate,
                                                           RedisAdvancedProperties redisAdvancedProperties,
                                                           ObjectMapper objectMapper) {
        RedisBloomFilterServiceImpl service = new RedisBloomFilterServiceImpl(redisTemplate, redisAdvancedProperties, objectMapper);
        log.info("Redis布隆过滤器服务初始化完成");
        return service;
    }

    /**
     * 配置分布式锁服务
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "redis.advanced.distributed-lock", name = "enabled", havingValue = "true", matchIfMissing = true)
    public RedisLockService redisLockService(RedissonClient redissonClient,
                                             RedisAdvancedProperties redisAdvancedProperties) {
        RedisLockServiceImpl service = new RedisLockServiceImpl(redissonClient, redisAdvancedProperties);
        log.info("分布式锁服务初始化完成");
        return service;
    }
}
